#include <linux/proc_fs.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqreturn.h>
#include <linux/module.h>
#include <linux/device.h>


static int major;
static unsigned char buff[100];
static struct class *led_class;

//unsigned int beep_gpio = 129;    	//对照原理图       蜂鸣器     GPIO5_IO1
unsigned int led_gpio = 3;      	//对照原理图       led     GPIO1_IO3

/*LED引脚GPIO1_IO3配置复用功能寄存器, 0x20E0068*/
volatile unsigned int *IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03;

/*LED引脚GPIO1_IO3配置输入输出寄存器, 0x209C004*/
volatile unsigned int *GPIO1_GDIR;

/*LED引脚GPIO1_IO3配置寄存器, 0x209C000*/
volatile unsigned int *GPIO1_DR;


static int led_open (struct inode *node, struct file *filp)
{
	printk("led_open\n");
//	printk("%s %s %d\n",__FILE__, __FUNCTION__, __LINE__);
	/*使能GPIO1功能*/
	*IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 &= ~0x0f;   //清除最后四位
	*IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 |= 0x05;    //设置为GPIO1功能

	/*设置GPIO1_IO3方向为输出*/
	*GPIO1_GDIR |= (1<<3);

	return 0;
}

static ssize_t led_read (struct file *filp, char *buf, size_t size, loff_t *offset)
{
	int err;

	printk("led_drv_read\n");

	/*read led_gpio value*/
	buff[0] = *GPIO1_DR & (1<<3);
	
	err = copy_to_user(buf, buff, 1);

	return buff[0];  
}

static ssize_t led_write (struct file *filp, char *buf, size_t size, loff_t *offset)
{
	int err;

	printk("led_drv_write\n");
	
	err = copy_from_user(buff, buf, 1);

	/*向DR寄存器写入值*/
	if(buff[0]){
		*GPIO1_DR |= (1 << 3);
	}else{
		*GPIO1_DR &= ~(1 << 3);
	}

	return 1;  
}


static int led_release (struct inode *node, struct file *filp)
{
	printk("led_release\n");
	return 0;
}

/*1.定义 file_operations 结构体*/
static const struct file_operations led_fops = {
    .owner 		= THIS_MODULE,
	.read		= led_read,
	.write 		= led_write,
	.open		= led_open,
	.release    = led_release,
};


/*3.入口函数*/
static int led_init(void)
{
	int err;
	/************* 1.注册设备，返回设备号 ************/
	major = register_chrdev(0,"led_drv",&led_fops);

	/*2.在内核中创建设备*/
	led_class = class_create(THIS_MODULE, "led_class");
	if (IS_ERR(led_class)) {
		printk("led class create failed!\n");
	}

	/*3.在/dev下面创建设备节点*/
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "led_drv");

	/************* 4.初始化led引脚 ************/
	/*映射GPIO寄存器*/
	IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = ioremap(0x20E0068, 4);
	/*映射GPIO方向寄存器*/
	GPIO1_GDIR = ioremap(0x209C004, 4);
	/*映射GPIO设置值寄存器*/
	GPIO1_DR = ioremap(0x209C000, 4);

	printk("led_init\n");
	
	return 0;
}

/*4.退出函数*/
static void led_exit(void)
{
	iounmap(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03);
	iounmap(GPIO1_GDIR);
	iounmap(GPIO1_DR);

	//卸载设备
	unregister_chrdev(major,"led_fops");

	//销毁设备
	device_destroy(led_class, MKDEV(major, 0));
	//删除设备类
	class_destroy(led_class);

	printk("led_exit\n");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

